//
//  stats_client.cpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2013-2014 Razvan Coca (razvan dot coca at  gmail dot com)
// This is mostly generated code. Generator is distributed under GPL. Edit it to suit your needs.
// 



#include "logging/logging.hpp"
#include "ConfigMap.hpp"
#include "Stats_ClientOptions.hpp"
#include "components/application/stats_mcast_client.hpp"
#include "components/encrypt/utils.hpp"

stats_message_t make_get_request(std::string const& key)
{
    stats_message_t query_message;
    stats_data qdata;
    stats_val qval;
    qval.set_value_type(stats_val::null);
    qdata.mutable_value()->CopyFrom(qval);
    qdata.set_name(key);
    qdata.set_timestamp(time(nullptr));
    query_message.set_type(stats_message_t::request_get);
    query_message.mutable_data()->CopyFrom(qdata);
    return query_message;
}
stats_message_t make_set_request(std::string const& key,float value)
{
    stats_message_t query_message;
    stats_data qdata;
    stats_val qval;
    qval.set_value_type(stats_val::cont);
    qval.set_value(value);
    qdata.set_name(key);
    qdata.set_timestamp(time(nullptr));
    qdata.mutable_value()->CopyFrom(qval);
    query_message.set_type(stats_message_t::request_set);
    query_message.mutable_data()->CopyFrom(qdata);
    return query_message;
}
bool has_key(ConfigMap& map, const char* key)
{
    try{
        map[key];
        return true;
    }
    catch(std::exception& e)
    {
        return false;
    }
}

int main(int argc, char* argv[])
{
    try
    {
        ConfigMap client_config(new Stats_ClientOptions,"stats_client.ini",argc,argv);
        if(client_config["help"].get_int())return 1;

        init_log(argv[0],client_config["log.path"].get_string());
        LOG(INFO)<<client_config;

        ba::io_service ios;
        crypto_buf_t iv=HexDecodeString(client_config["encrypt.iv"].get_string().c_str());
        crypto_buf_t key=HexDecodeString(client_config["encrypt.key"].get_string().c_str());
        endpoint conf_local_if=client_config["net.local_if"].get_endpoint();
        endpoint mgroup=client_config["net.mgroup"].get_endpoint();

        udp_endpoint_t local_if(ba::ip::address::from_string(conf_local_if.address),0);
        udp_endpoint_t mcast_group(ba::ip::address::from_string(mgroup.address),mgroup.port);
        int ttl=client_config["net.ttl"].get_int();
        bt::millisec flight_base(client_config["net.flight_base"].get_int());
        bt::millisec flight_incr(client_config["net.flight_incr"].get_int());
        int nitems=client_config["net.nitems"].get_int();
        std::string cluster(client_config["net.cluster"].get_string());
        std::string node(client_config["net.node"].get_string());

        if(has_key(client_config,"set.key")&&has_key(client_config,"get.key"))
            throw std::logic_error("Only one of get/set actions can be requested");
        else if(!has_key(client_config,"set.key")&&!has_key(client_config,"get.key"))
            throw std::logic_error("At least one of get/set actions must be requested");
        stats_mcast_client Client(ios,local_if,mcast_group,ttl,iv,key,flight_base,flight_incr,nitems,cluster,node);
        stats_message_t query_message;
        try{
            query_message=make_get_request(client_config["get.key"].get_string());
            Client.query(query_message);
        }
        catch(std::exception &e)
        {
            LOG(INFO)<<"error:"<<e.what();
            //throw std::runtime_error(std::string(e.what())+" No action get requested");
        }
        try{
            query_message=make_set_request(client_config["set.key"].get_string(),client_config["set.value"].get_double());
            Client.query(query_message);
        }
        catch(std::exception &e)
        {
            LOG(INFO)<<"error:"<<e.what();
            //throw std::runtime_error(std::string(e.what())+" No action set requested");
        }

        std::vector<stats_message_t> results=Client.get_results();
        for(auto const& r:results)
        {
            LOG(INFO)<<r.source().cluster()<<"/"<<r.source().node()<<" "<<
                        r.data().name()<<":"<<r.data().value().value()
                    <<", "<<r.data().timestamp();
        }
        results.clear();
        Client.stop();
    }
    catch(std::exception const& e)
    {
        LOG(ERROR)<<__FUNCTION__<<" "<<e.what();
    }

    return 0;
}
